package thread;

//单例模式-饿汉模式-线程安全
class Singleton {
    //类一加载这个对象直接就加载出来
    private static Singleton instance = new Singleton();
    //这里只涉及到多个线程对同一个变量进行读取
    public static Singleton getInstance() {
        return instance;
    }

    //设置为私有则只能通过getInstance这个方法获取这个对象
    //设置为私有，保证了对象的唯一性（单例模式）
    private Singleton() {

    }
}
//单例模式-懒汉模式-线程不安全
class Singletonlazy {
    //创建对象其实也分为了好几步，并不是“原子性”，
    // 编译器会在不影响代码逻辑之下对代码进行指令重排序以提高代码效率
    //在单线程的情况下是没有问题的，但是如果遇到多线程就可能会出问题，所以要加volatile关键字
    private static volatile Singletonlazy instance = null;
    //类一加载这个对象不会直接就加载出来而是需要用到才创建
    //线程不安全
    public static Singletonlazy getInstance1() {
        //这里分为了两步，先判断再创建，线程不安全（不符合原子性）
        //如果多个线程修改同一个变量就会出现bug
        if (instance == null) {
            instance = new Singletonlazy();
        }
        return instance;
    }
    //可以对上面的代码进行加锁操作保证线程安全但是加锁会有比加大的开销
    //且在第一次创建完后这个锁就已经没有必要了
    public static Singletonlazy getInstance2() {
        //这里对“先判断再创建”进行加锁，线程安全
        synchronized (Singletonlazy.class) {
            if (instance == null) {
                instance = new Singletonlazy();
            }
        }
        return instance;
    }
    //对上面的代码进行优化，在前面加一个if判断
    // 使得后面再想获取这个对象时就不需要加锁了
    public static Singletonlazy getInstance3() {
        //第一个if与第二个if刚好相同看似没有必要实则十分有意义
        //第一个if用于判断是否需要加锁，如果还没创建对象则应加锁防止线程不安全
        if (instance==null) {
            synchronized (Singletonlazy.class) {
                //第二个if用于判断是否需要创建对象
                if (instance == null) {
                    instance = new Singletonlazy();
                }
            }
        }
        return instance;
    }
    //设置为私有，保证了对象的唯一性（单例模式）
    private Singletonlazy(){
    }
}

public class demo4 {
    public static void main(String[] args) {
//        因为构造方法设置为私有所以不能创造这个对象
//        Singleton instance = new Singleton();
        Singleton instance = Singleton.getInstance();
        Singletonlazy instancelazy = Singletonlazy.getInstance3();
    }
}
